package engine.game.level;

import java.awt.Point;

import engine.entities.Entity;
import engine.game.Tickable;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

public class EntityMap implements Tickable {

    private Entity[][] entities;
    private int width;
    private int height;
    
    private String filePath = "\\test_level_entitymap.cfg";

    public EntityMap(Entity[][] entities) {
        this.width = entities.length;
        this.height = entities[0].length;
        this.entities = entities;
    }

    /**
     * Width getter
     *
     * @return Returns the width of the EntityMap
     */
    public int width() {
        return width;
    }

    /**
     * Height getter
     *
     * @return Returns the height of the EntityMap
     */
    public int height() {
        return height;
    }

    /**
     * Accesses the Entity at a specific location
     *
     * @param x The x coordinate of the desired Tile
     * @param y The y coordinate of the desired Tile
     *
     * @return Returns the tile at the specified location
     */
    public Entity entityAt(Point coords) {
        int x = coords.x;
        int y = coords.y;
        if (x >= width || x < 0 || y >= height || y < 0) {
            return null;
        }
        return entities[x][y];
    }

    /**
     * Adds an entity to the map.
     *
     * @param ent The Entity to add
     * @param x   the x coordinate of the entity
     * @param y   the y coordinate of the entity
     */
    public void addEntity(Entity ent, Point coords) {
        entities[coords.x][coords.y] = ent;
    }

    /**
     * Moves an entity to a different location on the map
     *
     * @param x0
     * @param y0
     * @param x
     * @param y
     */
    public void moveEntityTo(Point oldCoords, Point newCoords) {
        Entity ent = entities[oldCoords.x][oldCoords.y];
        entities[oldCoords.x][oldCoords.y] = null;
        entities[newCoords.x][newCoords.y] = ent;
    }

    /**
     * Ticks the entities in the map
     */
    @Override
    public void tick() {
        for (Entity[] line : entities) {
            for (Entity ent : line) {
                if (ent == null) {
                    continue;
                }
                else if (ent instanceof Tickable) {
                    ((Tickable) ent).tick();
                }
            }
        }
    }

    public String filePath() {
        return filePath;
    }

    public void setFilePath(String filePath) {
        this.filePath = filePath;
    }
    
    public void applyResize(Level.LevelResize resize) {
        int oldWidth = this.width;
        int oldHeight = this.height;

        this.width = oldWidth + resize.getAddLeft() + resize.getAddRight() - resize.getRemLeft() - resize.getRemRight();
        this.height = oldHeight + resize.getAddTop() + resize.getAddBot() - resize.getRemTop() - resize.getRemBot();

        Entity[][] newEnts = new Entity[width][height];

        for (int i = 0; i < newEnts.length; i++) {
            for (int j = 0; j < newEnts[0].length; j++) {
                int oldI = i - resize.getAddLeft();
                int oldJ = j - resize.getAddTop();
                if (oldI < 0 || oldI >= oldWidth) {
                    newEnts[i][j] = null;
                }
                else if (oldJ < 0 || oldJ >= oldHeight) {
                    newEnts[i][j] = null;
                }
                else {
                    newEnts[i][j] = entities[oldI][oldJ];
                }
            }
        }

        entities = newEnts;
    }

    public String[] getContent() {
        ArrayList<String> cont = new ArrayList<>();

        Map<Entity, Integer> key = new HashMap<>();
        ArrayList<String> lines = new ArrayList<>();
        int nextId = 0;

        for (int y = 0; y < entities[0].length; y++) {
            String line = "line" + y + " =";
//            for (int x = 0; x < entities.length; x++) {
//                Entity nextEnt = entityAt(new Point(x, y));
//                if (!key.containsKey(nextEnt)) {
//                    key.put(nextEnt, nextId);
//                    nextId++;
//                }
//                line += "\t" + key.get(nextEnt);
//            }

            for (int i = 0; i < width(); i++) {
                line += "-1";
                if (i < width - 1) {
                    line += "\t";
                }
            }

            lines.add(line);
        }

        cont.add("KEY");
        cont.add("{");
//        for (Entity ent : key.keySet()) {
//            cont.add(key.get(ent) + " = " + "null");
//        }
        cont.add("-1 = VOID");
        cont.add("}");

        cont.add("MAP");
        cont.add("{");
        for (String line : lines) {
            cont.add(line);
        }
        cont.add("}");

        String[] result = new String[cont.size()];
        for (int i = 0; i < cont.size(); i++) {
            result[i] = cont.get(i);
        }

        return result;
    }

    public void save(String filePath) {
        try {
            File outputFile = new File(filePath);
            try (FileWriter fw = new FileWriter(outputFile);
                    PrintWriter pw = new PrintWriter(fw)) {

                String[] content = getContent();
                for (String line : content) {
                    pw.println(line);
                }

            }
        }
        catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    public void save() {
        this.save(this.filePath());
    }

}
